clausura::[(Int,Int)] -> [(Int,Int)]
clausura [] = []
clausura [x] = [x]
clausura (x:y:ys) 
		| snd x == fst y = [x] ++ [y] ++ [(fst x, snd y)] ++ transitiva x ys ++ transitiva y ys ++ clausura (y:ys)
		| otherwise = [x] ++ [y] ++ transitiva x ys ++ transitiva y ys ++ clausura (y:ys)

transitiva::(Int,Int) -> [(Int,Int)] -> [(Int,Int)]
transitiva x [] = []
transitiva x (y:ys) 
		| (snd x == fst y) &&  (fst x == snd y) = [(fst x,snd y)] ++ [(fst y,snd x)] ++ transitiva x ys
		| snd x == fst y = [(fst x,snd y)] ++ transitiva x ys 
		| fst x == snd y = [(fst y,snd x)] ++ transitiva x ys
		| otherwise = transitiva x ys 	

igual :: (Int,Int) -> (Int,Int) -> Bool
igual x y = (fst x == fst y) && (snd x == snd y)

pertenece::(Int,Int) -> [(Int,Int)] -> Bool --elem x xs me devuelve un booleano y nub xs saca pares repetidos de una lista poner import data.list
pertenece _ [] = False
pertenece x (y:ys) = (igual x y) || pertenece x ys

filtrar::[(Int,Int)] -> [(Int,Int)]
filtrar [] = []
filtrar (x:xs)
		| pertenece x xs = filtrar xs
		| otherwise = [x] ++ filtrar xs

clausuraT::[(Int,Int)] -> [(Int,Int)]
clausuraT xs 
	| esPosible xs = clausuraT ys
	| otherwise = xs
		where ys = filtrar (clausura xs) 

adyacentes:: (Eq a) => [(a,a)]->[(a,a)]
adyacentes xs = [(fst(n),snd(m))|n<-xs,m<-xs,snd(n)==fst(m)]   

completa::[(Int,Int)]->[(Int,Int)]
completa xs = xs ++ adyacentes xs

esPosible::[(Int,Int)]->Bool
esPosible xs = length([(fst(n),snd(m))|n<-adyacentes xs,m<-xs,snd(n)==fst(m)])/=0


--Fuerza bruta!!
clausura_transitiva :: (Eq a) => [(a,a)] -> [(a,a)]
clausura_transitiva xs = eliminar_repetidos (trans (xs++adyacentes xs))
 
trans :: (Eq a) => [(a,a)] -> [(a,a)]
trans [] = []
trans ((a,b):xs) = ins (a,b) (trans xs)
 
ins :: (Eq a) => (a,a) -> [(a,a)] ->  [(a,a)]
ins (a,b) [] =  [(a,b)]
ins (a,b) ((c,d):xs) = if condition then
                           (c,d) : trans ((fst (a,b), snd (c,d)) : (ins (a,b) xs))
                       else
                           (c,d) : ins (a,b) xs
                       where
                           --condition nos dice si hay "puente" y si el elemento a agregar no esta
                           condition = snd (a,b) == fst (c,d) &&  notElem (fst (a,b), snd (c,d)) xs
 
eliminar_repetidos :: (Eq a) => [a] -> [a]
eliminar_repetidos [] = []
eliminar_repetidos (x:xs) = x : eliminar_repetidos (filter (/=x) xs)

tr:: (Eq a)=> (a,a) -> (a,a) -> (a,a)
tr (a,b) (c,d)
	| snd (a,b) == fst (c,d) = (fst(a,b),snd(c,d))
	| otherwise = (a,b) 
	
